/**
 * @author Ahammer
 * @date   2009 12
 * @update 2009 12 parameters
 * @update 2011 01 added 16 bit support
 */

/*
 * This file is part of Iqm.
 * Copyright (c) 2010-2011 Helmut Ahammer
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package opgui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.image.renderable.ParameterBlock;
import java.text.DecimalFormat;

import javax.media.jai.JAI;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.ROIShape;
import javax.media.jai.RenderedOp;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBox;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JSpinner;
import javax.swing.JToolBar;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.InternationalFormatter;

import main.Board;
import main.IqmTools;
import main.Tank;

public class IqmWhiteBalanceGUI  extends IqmOperatorJFrame
							    implements IqmOperatorGUIBuilder, ActionListener, ChangeListener{

	private  ParameterBlockJAI    pbJAI    = null;  //  @jve:decl-index=0:

	private  JRadioButtonMenuItem  buttROI            = null;
	private  JRadioButtonMenuItem  buttManual         = null;	
	private  JRadioButtonMenuItem  buttMethodHidden   = null;
	private  JToolBar              jToolBarMethod     = null;
	private  ButtonGroup           buttGroupMethod    = null;
	
	private  JLabel 			   jLabelInput        = null;
	private  JLabel 			   jLabelOutput	      = null;
		
	private JPanel 				 	jPanelInR		= null;	
	private JLabel				 	jLabelInR		= null;
	private JSpinner				jSpinnerInR		= null;	
	private JPanel 				 	jPanelInG		= null;	
	private JLabel				 	jLabelInG		= null;
	private JSpinner				jSpinnerInG		= null;
	private JPanel 				 	jPanelInB		= null;	
	private JLabel				 	jLabelInB		= null;
	private JSpinner				jSpinnerInB		= null;
	
	private JPanel 				 	jPanelOutR		= null;	
	private JLabel				 	jLabelOutR		= null;
	private JSpinner				jSpinnerOutR	= null;	
	private JPanel 				 	jPanelOutG		= null;	
	private JLabel				 	jLabelOutG		= null;
	private JSpinner				jSpinnerOutG	= null;
	private JPanel 				 	jPanelOutB		= null;	
	private JLabel				 	jLabelOutB		= null;
	private JSpinner				jSpinnerOutB	= null;
	
	private  JCheckBox 	    jCheckBoxLinkIn	   = null;
	private  JCheckBox 	    jCheckBoxLinkOut   = null;

	
	/**
	 * constructor
	 */
	public IqmWhiteBalanceGUI() {

	}


	/**
	 * This method sets the current parameter block to the argument
	 * @param ParameterBlockJAI pb
	 *
	 */
	@Override
	public void setParameterBlock(ParameterBlockJAI arg){
		pbJAI = arg;
		//there are not any parameters
		IqmTools.setCurrParameterBlockJAI(pbJAI);	
	}
	/**
	 * This method sets the current parameter block
	 * The individual values of the GUI current ParameterBlock
	 *
	 */
	@Override
	public void setParameterBlock(){

		if (buttROI.isSelected())     pbJAI.setParameter("Method", 0);
		if (buttManual.isSelected())  pbJAI.setParameter("Method", 1);

		pbJAI.setParameter("InR", ((Number)jSpinnerInR.getValue()).intValue());
		pbJAI.setParameter("InG", ((Number)jSpinnerInG.getValue()).intValue());
		pbJAI.setParameter("InB", ((Number)jSpinnerInB.getValue()).intValue());
		
		pbJAI.setParameter("OutR", ((Number)jSpinnerOutR.getValue()).intValue());
		pbJAI.setParameter("OutG", ((Number)jSpinnerOutG.getValue()).intValue());
		pbJAI.setParameter("OutB", ((Number)jSpinnerOutB.getValue()).intValue());
		
		if (jCheckBoxLinkIn.isSelected())   pbJAI.setParameter("LinkIn", 1);
		if (!jCheckBoxLinkIn.isSelected())  pbJAI.setParameter("LinkIn", 0);
		if (jCheckBoxLinkOut.isSelected())  pbJAI.setParameter("LinkOut", 1);
		if (!jCheckBoxLinkOut.isSelected()) pbJAI.setParameter("LinkOut", 0);
	
		IqmTools.setCurrParameterBlockJAI(pbJAI);	
	}
	
	/**
	 * This method sets the current parameter values
	 */
	@Override
	public void setParameterValues(){
		int idx = IqmTools.getCurrManagerImgIndex();
	    PlanarImage pi = Tank.getCurrentTankImageAt(idx); 
	    if (pi == null){
	    	   System.out.println("IqmWhiteBalanceGUI: Current image not defined");
	    	   return;
	    }
		if (pbJAI.getIntParameter("Method") == 0) buttROI.setSelected(true);
		if (pbJAI.getIntParameter("Method") == 1) buttManual.setSelected(true);

	    jSpinnerInR.removeChangeListener(this);
	    jSpinnerInG.removeChangeListener(this);	    	    
	    jSpinnerInB.removeChangeListener(this);	    	    
	    jSpinnerOutR.removeChangeListener(this);	    	     	    
	    jSpinnerOutG.removeChangeListener(this);
	    jSpinnerOutB.removeChangeListener(this);
	    
	    jSpinnerInR.setValue(pbJAI.getIntParameter("InR"));
	    jSpinnerInG.setValue(pbJAI.getIntParameter("InG"));
	    jSpinnerInB.setValue(pbJAI.getIntParameter("InB"));
	    jSpinnerOutR.setValue(pbJAI.getIntParameter("OutR"));
	    jSpinnerOutG.setValue(pbJAI.getIntParameter("OutG"));
	    jSpinnerOutB.setValue(pbJAI.getIntParameter("OutB"));
	    
	    jSpinnerInR.addChangeListener(this);
	    jSpinnerInG.addChangeListener(this);
	    jSpinnerInB.addChangeListener(this);
	    jSpinnerOutR.addChangeListener(this);
	    jSpinnerOutG.addChangeListener(this);
	    jSpinnerOutB.addChangeListener(this);
	    
	    if (pbJAI.getIntParameter("LinkIn") == 0)  jCheckBoxLinkIn.setSelected(false);
	    if (pbJAI.getIntParameter("LinkIn") == 1)  jCheckBoxLinkIn.setSelected(true);
	    if (pbJAI.getIntParameter("LinkOut") == 0) jCheckBoxLinkOut.setSelected(false);
	    if (pbJAI.getIntParameter("LinkOut") == 1) jCheckBoxLinkOut.setSelected(true);
	    
	    
		if (buttROI.isSelected()){
			jCheckBoxLinkIn.setSelected(false);
			jSpinnerInR.setEnabled(false);	
			jSpinnerInG.setEnabled(false);	
			jSpinnerInB.setEnabled(false);	
		}
	}

	/**
	 * This method creates and shows the GUI
	 */
	@Override
	public void createIqmOperatorGUI() {
		//opGUIFrame = new ImgProcFuncJFrame();  //actionPerforemd events werden in dieser Klasse abgehandelt
		//opGUIFrame = new IqmWhiteBalanceGUI();      //actionPerforemd events werden in dieser Klasse abgehandelt
		//this.getJContentPane();
		this.initialize(); //Aufruf von ImgProcFuncJFrame
		this.setTitle("WhiteBalance");
		PlanarImage pi = Tank.getCurrentTankImageAt(IqmTools.getCurrManagerImgIndex());
		int numBands = pi.getNumBands();
		String type = IqmTools.getImgTyp(pi);
		double typeGreyMax = IqmTools.getImgTypeGreyMax(pi);  	
		//Dimension dim = this.getSize();
		//this.setSize(dim.width, dim.height + 80);
		//this.setPreferredSize(new Dimension(800, 600));
		this.getJContentPane().add(getJToolBarMethod(),  getGridBagConstraintsButtonMethodGroup());		
		this.getJContentPane().add(getJLabelInput(),     getGridBagConstraintsLabelInput());
		this.getJContentPane().add(getJLabelOutput(),    getGridBagConstraintsLabelOutput());		
		this.getJContentPane().add(getJPanelInR(),       getGridBagConstraintsInR());
		this.getJContentPane().add(getJPanelInG(),       getGridBagConstraintsInG());
		this.getJContentPane().add(getJPanelInB(),       getGridBagConstraintsInB());
		this.getJContentPane().add(getJPanelOutR(),      getGridBagConstraintsOutR());
		this.getJContentPane().add(getJPanelOutG(),      getGridBagConstraintsOutG());
		this.getJContentPane().add(getJPanelOutB(),      getGridBagConstraintsOutB());			
		this.getJContentPane().add(getJCheckBoxLinkIn(), getGridBagConstraintsLinkIn());
		this.getJContentPane().add(getJCheckBoxLinkOut(),getGridBagConstraintsLinkOut());

		this.pack();
		
		//this.repaint();
		if (pbJAI == null) pbJAI = new ParameterBlockJAI("IqmWhiteBalance");  //nur wenn das erste mal aufgerufen
		//pbJAI = new ParameterBlockJAI("IqmWhiteBalance"); //immer der default Block
		IqmTools.setCurrParameterBlockJAI(pbJAI);
		this.setParameterValues();
	
		//Set image or ROI dependent initial values;	
		if (numBands == 1) {//Grey value image
			jLabelInR.setText("Grey");
			jLabelOutR.setText("Grey");
			jPanelInG.setVisible(false);
			jPanelInB.setVisible(false);
			jPanelOutG.setVisible(false);
			jPanelOutB.setVisible(false);
			jCheckBoxLinkIn.setVisible(false);
			jCheckBoxLinkOut.setVisible(false);					
		}
		
		if (buttROI.isSelected()){
			jCheckBoxLinkIn.setSelected(false);
		    ROIShape roi = IqmTools.getLookDisplayJAI().getCurrROIShape();
			if (roi == null) {			
				Board.appendTexln("IqmWhiteBalanceOperator: ROI is not defined and null!");
				Board.appendTexln("IqmWhiteBalanceOperator: calculation with whole image!");
			}
			else{
				Board.appendTexln("IqmWhiteBalanceOperator: ROI is defined and valid");		
			}
		    ParameterBlock pb = new ParameterBlock();
		    pb.addSource(pi);   
		    pb.add(roi); // ROI
		    pb.add(1);          			//sampling
		    pb.add(1);         
		    RenderedOp meanOp = JAI.create("Mean", pb, null);
		    double[] mean = (double[])meanOp.getProperty("mean");
		    
			jSpinnerInR.setValue(Math.round(mean[0]));	
			if (numBands > 1) jSpinnerInG.setValue(Math.round(mean[1]));	
			if (numBands > 2) jSpinnerInB.setValue(Math.round(mean[2]));				
		}
		jSpinnerOutR.setValue(250.0/255.0 * typeGreyMax);
		jSpinnerOutG.setValue(250.0/255.0 * typeGreyMax);
		jSpinnerOutB.setValue(250.0/255.0 * typeGreyMax);
	    
		this.setParameterBlock();
	}

	//------------------------------------------------------------------------------
	private GridBagConstraints getGridBagConstraintsButtonMethodGroup(){
		GridBagConstraints gridBagConstraintsButtonMethodGroup = new GridBagConstraints();
		gridBagConstraintsButtonMethodGroup.gridx = 1;
		gridBagConstraintsButtonMethodGroup.gridy = 5;
		gridBagConstraintsButtonMethodGroup.gridwidth = 2;//?
		gridBagConstraintsButtonMethodGroup.insets = new Insets(20,0,20,0);  //top left bottom right		
		//gridBagConstraintsButtonMethodGroup.fill = GridBagConstraints.BOTH;
		return gridBagConstraintsButtonMethodGroup;
	}
	
	private  GridBagConstraints getGridBagConstraintsLabelInput(){
		GridBagConstraints gridBagConstraintsLabelInput = new GridBagConstraints();
		gridBagConstraintsLabelInput.gridx = 1;
		gridBagConstraintsLabelInput.gridy = 6;
		gridBagConstraintsLabelInput.gridwidth = 1;
		gridBagConstraintsLabelInput.insets = new Insets(10,0,10,0);  //top, left bottom right
		gridBagConstraintsLabelInput.anchor = GridBagConstraints.CENTER;
		//gridBagConstraintsLabelInput.fill = GridBagConstraints.BOTH;
		return gridBagConstraintsLabelInput;
	}
	private  GridBagConstraints getGridBagConstraintsLabelOutput(){
		GridBagConstraints gridBagConstraintsLabelOutput = new GridBagConstraints();
		gridBagConstraintsLabelOutput.gridx = 2;
		gridBagConstraintsLabelOutput.gridy = 6;
		gridBagConstraintsLabelOutput.gridwidth = 1;
		gridBagConstraintsLabelOutput.insets = new Insets(10,0,10,0);  //top, left bottom right
		gridBagConstraintsLabelOutput.anchor = GridBagConstraints.LINE_END;
		//gridBagConstraintsLabelOutput.fill = GridBagConstraints.BOTH;
		return gridBagConstraintsLabelOutput;
	}
	
	private GridBagConstraints getGridBagConstraintsInR(){
		GridBagConstraints gridBagConstraintsInR = new GridBagConstraints();
		gridBagConstraintsInR.gridx = 1;
		gridBagConstraintsInR.gridy = 7;
		gridBagConstraintsInR.gridwidth = 1;//?
		gridBagConstraintsInR.insets = new Insets(10,0,0,0);  //top left bottom right
		//gridBagConstraintsInR.fill = GridBagConstraints.BOTH;
		return gridBagConstraintsInR;
	}
	private GridBagConstraints getGridBagConstraintsInG(){
		GridBagConstraints gridBagConstraintsInG = new GridBagConstraints();
		gridBagConstraintsInG.gridx = 1;
		gridBagConstraintsInG.gridy = 8;
		gridBagConstraintsInG.gridwidth = 1;//?
		gridBagConstraintsInG.insets = new Insets(10,0,0,0);  //top left bottom right
		//gridBagConstraintsInG.fill = GridBagConstraints.BOTH;
		return gridBagConstraintsInG;
	}
	private GridBagConstraints getGridBagConstraintsInB(){
		GridBagConstraints gridBagConstraintsInB = new GridBagConstraints();
		gridBagConstraintsInB.gridx = 1;
		gridBagConstraintsInB.gridy = 9;
		gridBagConstraintsInB.gridwidth = 1;//?
		gridBagConstraintsInB.insets = new Insets(10,0,0,0);  //top left bottom right
		//gridBagConstraintsInB.fill = GridBagConstraints.BOTH;
		return gridBagConstraintsInB;
	}
	private GridBagConstraints getGridBagConstraintsOutR(){
		GridBagConstraints gridBagConstraintsOutR = new GridBagConstraints();
		gridBagConstraintsOutR.gridx = 2;
		gridBagConstraintsOutR.gridy = 7;
		gridBagConstraintsOutR.gridwidth = 1;//?
		gridBagConstraintsOutR.insets = new Insets(10,0,0,0);  //top left bottom right
		//gridBagConstraintsOutR.fill = GridBagConstraints.BOTH;
		return gridBagConstraintsOutR;
	}
	private GridBagConstraints getGridBagConstraintsOutG(){
		GridBagConstraints gridBagConstraintsOutG = new GridBagConstraints();
		gridBagConstraintsOutG.gridx = 2;
		gridBagConstraintsOutG.gridy = 8;
		gridBagConstraintsOutG.gridwidth = 1;//?
		gridBagConstraintsOutG.insets = new Insets(10,0,0,0);  //top left bottom right
		//gridBagConstraintsOutG.fill = GridBagConstraints.BOTH;
		return gridBagConstraintsOutG;
	}
	private GridBagConstraints getGridBagConstraintsOutB(){
		GridBagConstraints gridBagConstraintsOutB = new GridBagConstraints();
		gridBagConstraintsOutB.gridx = 2;
		gridBagConstraintsOutB.gridy = 9;
		gridBagConstraintsOutB.gridwidth = 1;//?
		gridBagConstraintsOutB.insets = new Insets(10,0,0,0);  //top left bottom right
		//gridBagConstraintsOutB.fill = GridBagConstraints.BOTH;
		return gridBagConstraintsOutB;
	}
	private  GridBagConstraints getGridBagConstraintsLinkIn(){
		GridBagConstraints gridBagConstraintsLinkIn = new GridBagConstraints();
		gridBagConstraintsLinkIn.gridx = 1;
		gridBagConstraintsLinkIn.gridy = 10;
		gridBagConstraintsLinkIn.anchor = GridBagConstraints.LINE_END;
		gridBagConstraintsLinkIn.insets = new Insets(10,0,20,0); //top left bottom right
		//gridBagConstraintsLinkIn.fill = GridBagConstraints.BOTH;
		return gridBagConstraintsLinkIn;
	}
	private  GridBagConstraints getGridBagConstraintsLinkOut(){
		GridBagConstraints gridBagConstraintsLinkOut = new GridBagConstraints();
		gridBagConstraintsLinkOut.gridx = 2;
		gridBagConstraintsLinkOut.gridy = 10;
		gridBagConstraintsLinkOut.anchor = GridBagConstraints.LINE_END;
		gridBagConstraintsLinkOut.insets = new Insets(10,0,20,0); //top left bottom right
		//gridBagConstraintsLinkOut.fill = GridBagConstraints.BOTH;
		return gridBagConstraintsLinkOut;
	}
	
	//------------------------------------------------------------------------------------------------------------------
	/**
	 * This method updates the GUI if needed
	 * This method overrides IqmOperatorJFrame
	 */
	@Override
	public void updateIqmOperatorGUI(){
		
	}
	
	//Buttons--------------------------------------------------------------------------------------------
	/**
	 * This method initializes the Option: 	
	 * @return javax.swing.JRadioButtonMenuItem	
	 */
	private  JRadioButtonMenuItem getJRadioButtonMenuButtROI() {
		//if (buttROI == null) {
			buttROI  = new JRadioButtonMenuItem();
			buttROI .setText("ROI");
			buttROI .setToolTipText("initial values taken from ROI");
			buttROI .addActionListener(this);
			buttROI.setActionCommand("parameter");
		//}
		return buttROI;
	}
	/**
	 * This method initializes the Option: 	
	 * @return javax.swing.JRadioButtonMenuItem	
	 */
	private  JRadioButtonMenuItem getJRadioButtonMenuButtManual() {
		//if (buttManual == null) {
			buttManual = new JRadioButtonMenuItem();
			buttManual.setText("Manual");
			buttManual.setToolTipText("initial values taken from spinners");
			buttManual.addActionListener(this);
			buttManual.setActionCommand("parameter");
		//}
		return buttManual;
	}

	/**
	 * This method initializes the hidden option	
	 * 	
	 * @return javax.swing.JRadioButtonMenuItem	
	 */
	private  JRadioButtonMenuItem getJRadioButtonMenuButtMethodHidden() {
		//if (buttMethodHidden == null) {
			buttMethodHidden = new JRadioButtonMenuItem();
			buttMethodHidden.setText("Hidden");
			buttMethodHidden.setVisible(false);
		//}
		return buttMethodHidden;
	}
	/**
	 * This method initializes jJToolBarBar	
	 * 	
	 * @return javax.swing.JToolBar	
	 */
	private   JToolBar getJToolBarMethod() {
//		if (jToolBarMethod== null) {
			jToolBarMethod = new JToolBar("Options");
			jToolBarMethod.setOrientation(0); // 0 Horizontal 1 Vertical orientation
			jToolBarMethod.add(getJRadioButtonMenuButtROI());
			jToolBarMethod.add(getJRadioButtonMenuButtManual());
			jToolBarMethod.add(getJRadioButtonMenuButtMethodHidden());
			//jToolBarMethod.addSeparator();
			this.setButtonGroupMethod();	//Gruppieren der JRadioButtons
//		}
		return jToolBarMethod;
	}
	private  void setButtonGroupMethod() {
		//if (ButtonGroup buttGroup == null) {
			buttGroupMethod = new ButtonGroup();
			buttGroupMethod.add(buttROI);
			buttGroupMethod.add(buttManual);
			buttGroupMethod.add(buttMethodHidden);
	}
	//Label Text --------------------------------------------------------------------------------------------
	/**
	 * This method initializes jLabelInput	
	 * @return javax.swing.JLabel	
	 */
	private  JLabel getJLabelInput() {
		if (jLabelInput	== null) {
			jLabelInput = new JLabel();
			jLabelInput.setText("Input");
		}
		return jLabelInput	;
	}
	/**
	 * This method initializes jLabelOutput	
	 * @return javax.swing.JLabel	
	 */
	private  JLabel getJLabelOutput() {
		if (jLabelOutput == null) {
			jLabelOutput = new JLabel();
			jLabelOutput.setText("Output");
		}
		return jLabelOutput	;
	}
	
	//Spinners------------------------------------------------------------------------------------
	/**
	 * This method initializes jJPanelInR	
	 * 	
	 * @return javax.swing.JPanel
	 */
	private JPanel getJPanelInR() {
		if (jPanelInR == null) {
			jPanelInR = new JPanel();
			jPanelInR.setLayout(new BorderLayout());
			jLabelInR = new JLabel("R: ");
			jLabelInR.setPreferredSize(new Dimension(50, 22));
			jLabelInR.setHorizontalAlignment(JLabel.RIGHT);
			SpinnerModel sModel = new SpinnerNumberModel(0, 0, 255, 1); //init, min, max, step
			jSpinnerInR = new JSpinner(sModel);
			jSpinnerInR.setPreferredSize(new Dimension(60, 22));
			jSpinnerInR.addChangeListener(this);
			JSpinner.DefaultEditor defEditor = (JSpinner.DefaultEditor)jSpinnerInR.getEditor()  ;
			JFormattedTextField ftf = defEditor.getTextField() ;
			InternationalFormatter intFormatter = (InternationalFormatter)ftf.getFormatter() ;
			DecimalFormat decimalFormat = (DecimalFormat)intFormatter.getFormat() ;
			decimalFormat.applyPattern("#");  //decimalFormat.applyPattern("#,##0.0")  ;
			
			jPanelInR.add(jLabelInR, 	 BorderLayout.WEST);
			jPanelInR.add(jSpinnerInR, BorderLayout.CENTER);			
		}
		return jPanelInR;
	}
	/**
	 * This method initializes jJPanelInG	
	 * 	
	 * @return javax.swing.JPanel
	 */
	private JPanel getJPanelInG() {
		if (jPanelInG == null) {
			jPanelInG = new JPanel();
			jPanelInG.setLayout(new BorderLayout());
			jLabelInG = new JLabel("G: ");
			jLabelInG.setPreferredSize(new Dimension(50, 22));
			jLabelInG.setHorizontalAlignment(JLabel.RIGHT);
			SpinnerModel sModel = new SpinnerNumberModel(0, 0, 255, 1); //init, min, max, step
			jSpinnerInG = new JSpinner(sModel);
			jSpinnerInG.setPreferredSize(new Dimension(60, 22));
			jSpinnerInG.addChangeListener(this);
			JSpinner.DefaultEditor defEditor = (JSpinner.DefaultEditor)jSpinnerInG.getEditor()  ;
			JFormattedTextField ftf = defEditor.getTextField() ;
			InternationalFormatter intFormatter = (InternationalFormatter)ftf.getFormatter() ;
			DecimalFormat decimalFormat = (DecimalFormat)intFormatter.getFormat() ;
			decimalFormat.applyPattern("#");  //decimalFormat.applyPattern("#,##0.0")  ;
			
			jPanelInG.add(jLabelInG, 	 BorderLayout.WEST);
			jPanelInG.add(jSpinnerInG, BorderLayout.CENTER);			
		}
		return jPanelInG;
	}
	/**
	 * This method initializes jJPanelInB	
	 * 	
	 * @return javax.swing.JPanel
	 */
	private JPanel getJPanelInB() {
		if (jPanelInB == null) {
			jPanelInB = new JPanel();
			jPanelInB.setLayout(new BorderLayout());
			jLabelInB = new JLabel("B: ");
			jLabelInB.setPreferredSize(new Dimension(50, 22));
			jLabelInB.setHorizontalAlignment(JLabel.RIGHT);
			SpinnerModel sModel = new SpinnerNumberModel(0, 0, 255, 1); //init, min, max, step
			jSpinnerInB = new JSpinner(sModel);
			jSpinnerInB.setPreferredSize(new Dimension(60, 22));
			jSpinnerInB.addChangeListener(this);
			JSpinner.DefaultEditor defEditor = (JSpinner.DefaultEditor)jSpinnerInB.getEditor()  ;
			JFormattedTextField ftf = defEditor.getTextField() ;
			InternationalFormatter intFormatter = (InternationalFormatter)ftf.getFormatter() ;
			DecimalFormat decimalFormat = (DecimalFormat)intFormatter.getFormat() ;
			decimalFormat.applyPattern("#");  //decimalFormat.applyPattern("#,##0.0")  ;
			
			jPanelInB.add(jLabelInB, 	 BorderLayout.WEST);
			jPanelInB.add(jSpinnerInB, BorderLayout.CENTER);			
		}
		return jPanelInB;
	}
	/**
	 * This method initializes jJPanelOutR	
	 * 	
	 * @return javax.swing.JPanel
	 */
	private JPanel getJPanelOutR() {
		if (jPanelOutR == null) {
			jPanelOutR = new JPanel();
			jPanelOutR.setLayout(new BorderLayout());
			jLabelOutR = new JLabel("R: ");
			jLabelOutR.setPreferredSize(new Dimension(50, 22));
			jLabelOutR.setHorizontalAlignment(JLabel.RIGHT);
			SpinnerModel sModel = new SpinnerNumberModel(0, 0, 255, 1); //init, min, max, step
			jSpinnerOutR = new JSpinner(sModel);
			jSpinnerOutR.setPreferredSize(new Dimension(60, 22));
			jSpinnerOutR.addChangeListener(this);
			JSpinner.DefaultEditor defEditor = (JSpinner.DefaultEditor)jSpinnerOutR.getEditor()  ;
			JFormattedTextField ftf = defEditor.getTextField() ;
			InternationalFormatter intFormatter = (InternationalFormatter)ftf.getFormatter() ;
			DecimalFormat decimalFormat = (DecimalFormat)intFormatter.getFormat() ;
			decimalFormat.applyPattern("#");  //decimalFormat.applyPattern("#,##0.0")  ;
			
			jPanelOutR.add(jLabelOutR, 	 BorderLayout.WEST);
			jPanelOutR.add(jSpinnerOutR, BorderLayout.CENTER);			
		}
		return jPanelOutR;
	}
	/**
	 * This method initializes jJPanelOutG	
	 * 	
	 * @return javax.swing.JPanel
	 */
	private JPanel getJPanelOutG() {
		if (jPanelOutG == null) {
			jPanelOutG = new JPanel();
			jPanelOutG.setLayout(new BorderLayout());
			jLabelOutG = new JLabel("G: ");
			jLabelOutG.setPreferredSize(new Dimension(50, 22));
			jLabelOutG.setHorizontalAlignment(JLabel.RIGHT);
			SpinnerModel sModel = new SpinnerNumberModel(0, 0, 255, 1); //init, min, max, step
			jSpinnerOutG = new JSpinner(sModel);
			jSpinnerOutG.setPreferredSize(new Dimension(60, 22));
			jSpinnerOutG.addChangeListener(this);
			JSpinner.DefaultEditor defEditor = (JSpinner.DefaultEditor)jSpinnerOutG.getEditor()  ;
			JFormattedTextField ftf = defEditor.getTextField() ;
			InternationalFormatter intFormatter = (InternationalFormatter)ftf.getFormatter() ;
			DecimalFormat decimalFormat = (DecimalFormat)intFormatter.getFormat() ;
			decimalFormat.applyPattern("#");  //decimalFormat.applyPattern("#,##0.0")  ;
			
			jPanelOutG.add(jLabelOutG, 	 BorderLayout.WEST);
			jPanelOutG.add(jSpinnerOutG, BorderLayout.CENTER);			
		}
		return jPanelOutG;
	}
	/**
	 * This method initializes jJPanelOutB	
	 * 	
	 * @return javax.swing.JPanel
	 */
	private JPanel getJPanelOutB() {
		if (jPanelOutB == null) {
			jPanelOutB = new JPanel();
			jPanelOutB.setLayout(new BorderLayout());
			jLabelOutB = new JLabel("B: ");
			jLabelOutB.setPreferredSize(new Dimension(50, 22));
			jLabelOutB.setHorizontalAlignment(JLabel.RIGHT);
			SpinnerModel sModel = new SpinnerNumberModel(0, 0, 255, 1); //init, min, max, step
			jSpinnerOutB = new JSpinner(sModel);
			jSpinnerOutB.setPreferredSize(new Dimension(60, 22));
			jSpinnerOutB.addChangeListener(this);
			JSpinner.DefaultEditor defEditor = (JSpinner.DefaultEditor)jSpinnerOutB.getEditor()  ;
			JFormattedTextField ftf = defEditor.getTextField() ;
			InternationalFormatter intFormatter = (InternationalFormatter)ftf.getFormatter() ;
			DecimalFormat decimalFormat = (DecimalFormat)intFormatter.getFormat() ;
			decimalFormat.applyPattern("#");  //decimalFormat.applyPattern("#,##0.0")  ;
			
			jPanelOutB.add(jLabelOutB, 	 BorderLayout.WEST);
			jPanelOutB.add(jSpinnerOutB, BorderLayout.CENTER);			
		}
		return jPanelOutB;
	}
	//jCheckBox--------------------------------------------------------------------------------------------

	/**
	 * This method initializes jCheckBoxLinkIn	
	 * 	
	 * @return javax.swing.JCheckBox	
	 */
	private  JCheckBox getJCheckBoxLinkIn() {
		if (jCheckBoxLinkIn == null) {
			jCheckBoxLinkIn = new JCheckBox();
			jCheckBoxLinkIn.setText("Link");
			jCheckBoxLinkIn.addActionListener(this);			
			jCheckBoxLinkIn.setActionCommand("parameter");			
		}
		return jCheckBoxLinkIn;
	}
	/**
	 * This method initializes jCheckBoxLinkOut	
	 * 	
	 * @return javax.swing.JCheckBox	
	 */
	private  JCheckBox getJCheckBoxLinkOut() {
		if (jCheckBoxLinkOut == null) {
			jCheckBoxLinkOut = new JCheckBox();
			jCheckBoxLinkOut.setText("Link");
			jCheckBoxLinkOut.addActionListener(this);			
			jCheckBoxLinkOut.setActionCommand("parameter");			
		}
		return jCheckBoxLinkOut;
	}
	

	//--------------------------------------------------------------------------------------------
	
	public void actionPerformed(ActionEvent e) {
		//System.out.println("IqmWhiteBalanceGUI: event e: " +e.getActionCommand());
		if ("reset".equals(e.getActionCommand())) {
			ParameterBlockJAI pbJAI = new ParameterBlockJAI("IqmWhiteBalance".toLowerCase());
			IqmTools.setCurrParameterBlockJAI(pbJAI);
			this.setParameterBlock(pbJAI);
			this.setParameterValues();
			//this.updateIqmOperatorGUI();  //if necessary here or some lines above
			this.reset();
		}
		if ("parameter".equals(e.getActionCommand())) {
			if (e.getSource() == buttROI){ //get ROI information	
				jCheckBoxLinkIn.setSelected(false);
				jSpinnerInR.setEnabled(false);	
				jSpinnerInG.setEnabled(false);	
				jSpinnerInB.setEnabled(false);	
			    ROIShape roi = IqmTools.getLookDisplayJAI().getCurrROIShape();
				if (roi == null) {			
					Board.appendTexln("IqmWhiteBalanceOperator: ROI is not defined and null!");
					Board.appendTexln("IqmWhiteBalanceOperator: calculation with whole image!");
				}
				else{
					Board.appendTexln("IqmWhiteBalanceOperator: ROI is defined and valid");		
				}
				PlanarImage pi = Tank.getCurrentTankImageAt(IqmTools.getCurrManagerImgIndex());
				int numBands = pi.getNumBands();
			    ParameterBlock pb = new ParameterBlock();
				pb.addSource(pi);	
				pb.removeSources();
				pb.removeParameters();
			    pb.addSource(pi);   
			    pb.add(roi); // ROI
			    pb.add(1);          			//sampling
			    pb.add(1);         
			    RenderedOp meanOp = JAI.create("Mean", pb, null);
			    double[] mean = (double[])meanOp.getProperty("mean");
			    
				jSpinnerInR.setValue(Math.round(mean[0]));	
				if (numBands > 1) jSpinnerInG.setValue(Math.round(mean[1]));	
				if (numBands > 2) jSpinnerInB.setValue(Math.round(mean[2]));		
			}
			if (e.getSource() == buttManual){
				jSpinnerInR.setEnabled(true);	
				jSpinnerInG.setEnabled(true);	
				jSpinnerInB.setEnabled(true);	
			}
		}
		this.setParameterBlock();
		//this.updateIqmOperatorGUI();  //if necessary here or some lines above
		//preview if selected
		if (this.isAutoPreviewSelected()){
			this.showPreview();
		}

	}

	//-------------------------------------------------------------------------------------------------



	@Override
	public void stateChanged(ChangeEvent e) {
		int inR  = ((Number)jSpinnerInR.getValue()).intValue();
		int inG  = ((Number)jSpinnerInG.getValue()).intValue();
		int inB  = ((Number)jSpinnerInB.getValue()).intValue();
		int outR  = ((Number)jSpinnerOutR.getValue()).intValue();
		int outG  = ((Number)jSpinnerOutG.getValue()).intValue();
		int outB  = ((Number)jSpinnerOutB.getValue()).intValue();
		
		if (buttROI.isSelected()){
			jCheckBoxLinkIn.setSelected(false);
		}
		if (jCheckBoxLinkIn.isSelected()){
			if (jSpinnerInR == e.getSource()) {
				jSpinnerInG.setValue(inR);
				jSpinnerInB.setValue(inR);
			}
			if (jSpinnerInG == e.getSource()) {
				jSpinnerInR.setValue(inG);
				jSpinnerInB.setValue(inG);
			}	
			if (jSpinnerInB == e.getSource()) {
				jSpinnerInR.setValue(inB);
				jSpinnerInG.setValue(inB);
			}	
		}
		if (jCheckBoxLinkOut.isSelected()){
			if (jSpinnerOutR == e.getSource()) {
				jSpinnerOutG.setValue(outR);
				jSpinnerOutB.setValue(outR);
			}
			if (jSpinnerOutG == e.getSource()) {
				jSpinnerOutR.setValue(outG);
				jSpinnerOutB.setValue(outG);
			}	
			if (jSpinnerOutB == e.getSource()) {
				jSpinnerOutR.setValue(outB);
				jSpinnerOutG.setValue(outB);
			}	
		}
		this.setParameterBlock();
		//this.updateIqmOperatorGUI();  //if necessary here or some lines above
		//preview if selected
		if (this.isAutoPreviewSelected()){
			this.showPreview();
		}
	}
	//-------------------------------------------------------------------------------------------------
	
	public static void main() {

		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				IqmWhiteBalanceGUI gui = new IqmWhiteBalanceGUI();
				gui.createIqmOperatorGUI();

			}
		});
	}



	
}//END
